use std::{fmt::Display, marker::PhantomData, ops::Deref};

use entity::{
    meeting_room::{ColumnTrait, EntityTrait, QueryFilter},
    sea_orm::ConnectionTrait,
    user::{admin, auth, custom},
};

use super::{
    auth::{User, UserType},
    UserNotFound, UserVerifyError,
};

pub trait AuthCheckTrait {
    fn do_check(ty: UserType) -> bool {
        ty == <Self as AuthCheckTrait>::user_type()
    }

    fn user_type() -> UserType;
}



pub struct AuthCheck<C: AuthCheckTrait> {
    user: User,
    _phantom: PhantomData<C>,
}

impl<C: AuthCheckTrait> Deref for AuthCheck<C> {
    type Target = User;

    fn deref(&self) -> &Self::Target {
        &self.user
    }
}

impl<C: AuthCheckTrait> AuthCheck<C> {
    pub fn new(user: User, _: C) -> Result<Self, AuthCheckFailureError> {
        if C::do_check(user.ty) {
            Ok(Self {
                user,
                _phantom: PhantomData,
            })
        } else {
            Err(AuthCheckFailureError)
        }
    }

    pub async fn new_with_auth<Db: ConnectionTrait>(
        db: &Db,
        auth: auth::Model,
        checker: C,
    ) -> Result<Self, UserVerifyError> {
        // select user
        let user = match C::user_type() {
            UserType::Custom => User::from((
                custom::Entity::find()
                    .filter(custom::Column::AuthId.eq(auth.id))
                    .one(db)
                    .await?
                    .ok_or(UserNotFound)?,
                auth,
            )),
            UserType::Admin => User::from((
                admin::Entity::find()
                    .filter(admin::Column::AuthId.eq(auth.id))
                    .one(db)
                    .await?
                    .ok_or(UserNotFound)?,
                auth,
            )),
        };

        Ok(Self::new(user, checker)?)
    }
}

#[derive(Default, Debug)]
pub struct AuthCheckFailureError;

impl Display for AuthCheckFailureError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "用户权限等级不足")
    }
}
